#ifndef GAMEENGINE_CORE_FACTORY_FACTORY_MANAGER_H
#define GAMEENGINE_CORE_FACTORY_FACTORY_MANAGER_H

#include <GameEngine/Core/core_settings.h>
#include <GameEngine/Core/string.h>

#include <map>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

class FactoryBuilder;


//========================================================


//! Manages the creation of objects using the concrete factory design pattern
/*!
 *  Caution: type T must have rtti support for this class to work. Furthermore, a
 *  class C can be bound to the factory builder if and only if it derives (directly
 *  or indirectly) from class T. This relationship should also be referenced in the
 *  RTTI support of class C.
 *
 *  Let's assume one has a MyClass class, derived from the MyParentClass class. A
 *  factory builder must be written for the MyClass class (see the FactoryBuilder
 *  class documentation for an example). Let's call it MyClass_Factory_Builder. A
 *  typical example of use of the factory manager class could then be:
 *  @code
 *  // Access the factory manager for class MyParentClass
 *  FactoryManager<MyParentClass>* manager = FactoryManager<MyParentClass>::instance();
 *  
 *  // For the moment, we cannot create an object of type MyClass using the factory
 *  MyParentClass* obj = manager->create_object<MyClass>(); // obj is a null pointer
 *  
 *  // Bind the factory builder for the MyClass class to the manager
 *  MyClass_Factory_Builder* builder = new MyClass_Factory_Builder();
 *  manager->bind<MyClass>(builder);
 *  
 *  // Now, we can create an object of type MyClass using the factory
 *  MyParentClass* obj2 = manager->create_object<MyClass>(); // obj2 is not a null pointer
 *  @endcode
 */
template <class T>
class FactoryManager {
	//! Typedef to handle this type of factory manager
	typedef FactoryManager<T> Self;
	GAMEENGINE_DECLARE_SINGLETON( Self )

public:
	virtual ~FactoryManager();

	template <class C> T* create_object();

	template <class C> bool bind(FactoryBuilder* builder);
	template <class C> bool unbind();

	void clear();

private:
	FactoryManager();

private:
	std::map<GEString,FactoryBuilder*> bindings_;
};


//========================================================

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#include <GameEngine/Core/Factory/factory_manager.hpp>

#endif
